using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;

namespace SharpMud.Server.Systems.Scripting.Runtime
{
    /// <summary>
    /// Provides a string-based parameter lookup mechanism for the dynamic invocation of
    /// scripts implementing IScript.
    /// </summary>
    public class ScriptExecutionContext
    {
        /// <summary>
        /// The hard-coded key that a script may use to assign a 'return' result through.
        /// </summary>
        public const string ReturnResultKEY = "_____returnResult";
        private Dictionary<string, object> _Parameters;

        public ScriptExecutionContext()
        {
            _Parameters = new Dictionary<string, object>();
        }
        public ScriptExecutionContext(params KeyValuePair<string, object>[] parameters)
        {
            _Parameters = new Dictionary<string, object>();
            foreach (KeyValuePair<string, object> kvp in parameters)
            {
                _Parameters.Add(kvp.Key, kvp.Value);
            }
        }

        public object this[string key]
        {
            get
            {
                object result;
                lock (this._Parameters)
                {
                    if (!_Parameters.ContainsKey(key))
                        result = null;
                    else
                        result = _Parameters[key];
                }
                return result;
            }
            set
            {
                lock (this._Parameters)
                {
                    if (this._Parameters.ContainsKey(key))
                        this._Parameters.Remove(key);
                    _Parameters.Add(key, value);
                }
            }
        }

        public T GetAs<T>(string key) where T : new()
        {
            return ((T)this[key]);
        }

        public void SetAs<T>(string key, T value) where T : new()
        {
            this[key] = value;
        }

        public object ReturnResult
        {
            get
            {
                return this[ReturnResultKEY];
            }
            set
            {
                this[ReturnResultKEY] = value;
            }
        }
        public T GetReturnResultAs<T>()
        {
            return ((T)this[ReturnResultKEY]);
        }

        public void SetReturnResultAs<T>(T value)
        {
            this[ReturnResultKEY] = value;
        }

        public int Count
        {
            get
            {
                return _Parameters.Count;
            }
        }

        public void Remove(string key)
        {
            lock (_Parameters)
            {
                if (_Parameters.ContainsKey(key))
                    _Parameters.Remove(key);
            }
        }

        public bool HasReturnResult
        {
            get
            {
                bool r;
                lock (_Parameters)
                {
                    r = _Parameters.ContainsKey(ReturnResultKEY);
                }
                return r;
            }
        }

        public Dictionary<string, object>.KeyCollection Keys
        {
            get
            {
                return _Parameters.Keys;
            }
        }

        internal CodeVariableDeclarationStatement GetParameterIntegrationStatement(string key, System.CodeDom.CodeArgumentReferenceExpression contextReference)
        {
            if (!this._Parameters.ContainsKey(key))
                throw new IndexOutOfRangeException();

            CodeExpression initExpression = new CodeArrayIndexerExpression(contextReference, new CodePrimitiveExpression(key));

            CodeVariableDeclarationStatement varDecl = new CodeVariableDeclarationStatement(this[key].GetType(), key, initExpression);

            return varDecl;
        }
    }
}
